package com.woniuxy.productservice.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.core.exception.WoniuxyException;
import com.woniuxy.core.model.Result;
import com.woniuxy.core.status.ProductState;
import com.woniuxy.core.status.TeamResevState;
import com.woniuxy.core.status.UserState;
import com.woniuxy.core.util.DateUtil;
import com.woniuxy.core.util.PageInfo;
import com.woniuxy.productclient.client.UserFeignClient;
import com.woniuxy.productclient.client.dto.UserInfoDto;
import com.woniuxy.productdao.mapper.TeamReservationMapper;
import com.woniuxy.productdao.model.TeamProduct;
import com.woniuxy.productdao.model.TeamReservation;
import com.woniuxy.productmodel.dto.TeamReservDto;
import com.woniuxy.productmodel.form.VenueListTeamReservForm;
import com.woniuxy.productservice.exception.ProductException;
import com.woniuxy.productservice.service.TeamProductService;
import com.woniuxy.productservice.service.TeamReservationService;
import com.woniuxy.util.MyRedisKeyUtil;
import com.woniuxy.util.MyRedisUtil;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.yaml.snakeyaml.events.Event;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 团课预约表 服务实现类
 * </p>
 *
 * @author 冉杰
 * @since 2024-01-15
 */
@Service
public class TeamReservationServiceImpl extends ServiceImpl<TeamReservationMapper, TeamReservation> implements TeamReservationService {

    @Autowired
    private TeamProductService teamProductService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private MyRedisKeyUtil myRedisKeyUtil;
    @Autowired
    private UserFeignClient ufc;

    /**
     * 用户预约团课
     * @param teamProductId 团课产品id
     * @param userId 用户id
     * @return
     */
    @Override
    public TeamReservDto addTeamReservation(Integer teamProductId, Integer userId) throws InterruptedException {
        TeamProduct teamProduct = teamProductService.getById(teamProductId);
        if (null==teamProduct) throw new ProductException(80001,"团课产品不存在");
        if (teamProduct.getTeamProductState() == ProductState.IS_DISABLED.getState()) throw new ProductException(80002,"团课产品被禁用");
        //判断用户的可用性
        Result<UserInfoDto> res1 = ufc.findUserById(userId);
        if (!res1.getFlag()) throw new ProductException(res1.getCode(),res1.getMsg());
        UserInfoDto userInfo = res1.getData();
        if (ObjectUtils.isEmpty(userInfo)) throw new ProductException(60004,"用户不存在");
        if (userInfo.getUserState()!= UserState.IS_ENABLE.getState()) throw new ProductException(60005,"用户未启用");
        if (userInfo.getAuthState()!=UserState.IS_AUTH.getState()) throw new ProductException(60006,"用户未实名认证");
        //判断该用户是否已有改团课的预约
        //判断用户该团课的预约如果存在非取消状态的预约，则认为是有效预约不能再发起，如果形成了订单，延时未支付自动取消预约
        boolean exists = new LambdaQueryChainWrapper<TeamReservation>(getBaseMapper())
                .eq(TeamReservation::getUserId, userId)
                .ne(TeamReservation::getReservationState, TeamResevState.CANCEL).exists();
        if (exists) throw new ProductException(60007,"用户存在改团课产品的有效预约");
        //开启分布式锁
        RLock fairLock = redissonClient.getFairLock(myRedisKeyUtil.lockObjectKey("teamProductId", teamProductId));
        boolean tryLock = fairLock.tryLock(20, TimeUnit.SECONDS);
        try {
            if (tryLock){
                //判断现有有效预约的人数是否已经达到团课的最大人数，支持开课了还能预约
                Long count = new LambdaQueryChainWrapper<TeamReservation>(getBaseMapper())
                        .in(TeamReservation::getReservationState, TeamResevState.RESERVIED.getState()
                                ,TeamResevState.OPEN_CLASS.getState())//已开课和预约中的总人数
                        .count();
                if (count == teamProduct.getMaxNum().longValue()) throw new ProductException(80004,"已达该团课预约上限");
                //发起预约
                TeamReservation teamReservation = new TeamReservation();
                teamReservation.setReservationState(TeamResevState.RESERVIED.getState());
                teamReservation.setUserId(userId);
                teamReservation.setUserName(userInfo.getUserName());
                teamReservation.setUserPhone(userInfo.getUserPhone());
                teamReservation.setReservationTime(DateUtil.dateTimeToString(new Date()));
                teamReservation.setTeamProductId(teamProductId);
                teamReservation.setTeamProductName(teamProduct.getTeamProductName());
                teamReservation.setVenueId(teamProduct.getVenueId());
                save(teamReservation);
                TeamReservDto dto = BeanUtil.toBean(teamReservation, TeamReservDto.class);
                return dto;
            }else {
                throw new WoniuxyException(99999,"网络或服务繁忙，请稍后再试");
            }
        } finally {
            fairLock.unlock();
        }
    }

    /**
     *用户查看团队预约详情
     * @param userId
     * @return
     */
    @Override
    public List<TeamReservDto> userListTeamReservation(Integer userId) {
        List<TeamReservation> list = list(new LambdaQueryWrapper<TeamReservation>()
                .eq(TeamReservation::getUserId, userId));
        List<TeamReservDto> dtos = BeanUtil.copyToList(list, TeamReservDto.class);
        return dtos;
    }

    /**
     * 商家端条件查看团课预约方法
     * @param form
     * @param venueId
     * @return
     */
    @Override
    public PageInfo<TeamReservDto> venueListTeamReservation(VenueListTeamReservForm form, Integer venueId) {
        Long current = form.getCurrent();
        Long size = form.getSize();
        Page<TeamReservation> page = new Page<>(current == null ? 1l : current, size == null ? 1l : size);
        LambdaQueryWrapper<TeamReservation> wrapper = new LambdaQueryWrapper<TeamReservation>()
                .eq(TeamReservation::getVenueId,venueId)
                .eq(!ObjectUtils.isEmpty(form.getReservationState()), TeamReservation::getReservationState, form.getReservationState())
                .eq(!ObjectUtils.isEmpty(form.getTeamProductName()), TeamReservation::getTeamProductName, form.getTeamProductName())
                .eq(!ObjectUtils.isEmpty(form.getUserName()), TeamReservation::getUserName, form.getUserName())
                .eq(!ObjectUtils.isEmpty(form.getUserPhone()), TeamReservation::getUserPhone, form.getUserPhone());
        page(page,wrapper);
        PageInfo<TeamReservDto> pageInfo = BeanUtil.toBean(page, PageInfo.class);
        List<TeamReservDto> list = BeanUtil.copyToList(page.getRecords(), TeamReservDto.class);
        pageInfo.setPages(page.getPages());
        pageInfo.setList(list);
        return pageInfo;
    }

    /**
     * 用户取消团课预约
     * @param reservationId
     * @param userId
     */
    @Override
    public void userCancelTeamReservation(Integer reservationId, Integer userId) {
        TeamReservation teamReservation = getById(reservationId);
        if (null==teamReservation) throw new ProductException(80001,"预约不存在");
        if (teamReservation.getUserId()!=userId) throw new ProductException(80003,"不是改用户的预约");
        if(teamReservation.getReservationState()!=TeamResevState.RESERVIED.getState()) throw new ProductException(80002,"只能取消预约了的预约");
        teamReservation.setReservationState(TeamResevState.CANCEL.getState());
        teamReservation.setCacelTime(DateUtil.dateTimeToString(new Date()));
        updateById(teamReservation);
    }

    /**
     * 商家端端给团课产品开课
     * @param teamProductId 产品id
     * @param venueId
     * 用户需要通过判断团课预约是已开课的状态才能下单
     */
    @Override
    public void venueOpenClass(Integer teamProductId, Integer venueId) {
        TeamProduct teamProduct = teamProductService.getById(teamProductId);
        if (null==teamProduct) throw new ProductException(80001,"产品不存在");
        if (teamProduct.getVenueId()!=venueId) throw new ProductException(80002,"不是该场馆的团课产品");
        List<TeamReservation> teamReservations = new LambdaQueryChainWrapper<TeamReservation>(getBaseMapper())
                .eq(TeamReservation::getTeamProductId, teamProductId)
                .eq(TeamReservation::getVenueId, venueId)
                .eq(TeamReservation::getReservationState, TeamResevState.RESERVIED.getState()).list();
        if (ObjectUtils.isEmpty(teamReservations)) throw new ProductException(80003,"该团课产品暂无有效预约");
        for (TeamReservation teamReservation : teamReservations) {
            teamReservation.setReservationState(TeamResevState.OPEN_CLASS.getState());
        }
        updateBatchById(teamReservations);
    }

    @Override
    public List<TeamReservDto> byProductId(Integer teamProductId) {
        LambdaQueryWrapper<TeamReservation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TeamReservation::getTeamProductId,teamProductId);
        List<TeamReservation> list = list(wrapper);
        return BeanUtil.copyToList(list,TeamReservDto.class);
    }
}
